import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

//horrible coding, needs to be re-written and cleaned up.
@SuppressWarnings("serial")
public class Snake extends JFrame implements KeyListener, Runnable {

    JPanel p1, p2;
    JButton[] lb = new JButton[200];
    JButton bonusfood;
    JTextArea t;
    int x = Launcher.WINDOW_WIDTH, y = Launcher.WINDOW_HEIGHT - 50, gu = 2, directionx = 1, directiony = 0, speed = 125, difference = 0, oldx, oldy, score = 0;
    int[] lbx = new int[300];
    int[] lby = new int[300];
    Point[] lbp = new Point[300];
    Point bfp = new Point();
    Thread myt;
    boolean food = false, runl = false, runr = true, runu = true, rund = true, bonusflag = true;
    Random r = new Random();
    JMenuBar mymbar;
    JMenu game, help, level;
    JLabel largeLabel;
    

    public void myvalue() {
        gu = 3;
        lbx[0] = PIECE_WIDTH;
        lby[0] = PIECE_HEIGHT;
        directionx = PIECE_WIDTH;
        directiony = 0;
        difference = 0;
        score = 0;
        food = false;
        runl = false;
        runr = true;
        runu = true;
        rund = true;
        bonusflag = true;
    }

    Snake() {
        super("Snake");
        setSize(Launcher.WINDOW_WIDTH, Launcher.WINDOW_HEIGHT);

        creatbar();

        myvalue();

        p1 = new JPanel();
        p2 = new JPanel();
        t = new JTextArea("Score ==> " + score);
        t.setEnabled(false);
        t.setBackground(Color.BLACK);

        bonusfood = new JButton();
        bonusfood.setEnabled(false);

        firstsnake();

        p1.setLayout(null);
        p2.setLayout(new GridLayout(0, 1));
        p1.setBounds(0, 0, x, y-SCOREBOARD_HEIGHT);
        p1.setBackground(Color.blue);
        p2.setBounds(0, y-SCOREBOARD_HEIGHT, x, SCOREBOARD_HEIGHT);
        p2.setBackground(Color.RED);

        p2.add(t);

        getContentPane().setLayout(null);
        getContentPane().add(p1);
        getContentPane().add(p2);
        
        largeLabel = new JLabel();
        largeLabel.setLocation(Launcher.WINDOW_WIDTH / 3, 0);
    	p1.add(largeLabel);
        
        this.setVisible(true);

        addKeyListener(this);
        myt = new Thread(this);
        myt.start();
    }

    public void firstsnake() {
        for (int i = 0; i < 3; i++) {
            lb[i] = new JButton(SNAKE_STRING.substring(i, i+1));
            lb[i].setMargin(new Insets(0, 0, 0, 0));
            lb[i].setEnabled(false);
            p1.add(lb[i]);
            lb[i].setBounds(lbx[i], lby[i], PIECE_WIDTH, PIECE_HEIGHT);
            lbx[i + 1] = lbx[i] - PIECE_WIDTH;
            lby[i + 1] = lby[i];
        }
    }

    public void creatbar() {
        mymbar = new JMenuBar();

        game = new JMenu("Game");

        JMenuItem newgame = new JMenuItem("New Game");
        JMenuItem exit = new JMenuItem("Exit");

        newgame.addActionListener(
                new ActionListener() {

                    public void actionPerformed(ActionEvent e) {
                        reset();
                    }
                });

        exit.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });

        game.add(newgame);
        game.addSeparator();
        game.add(exit);

        mymbar.add(game);

        level = new JMenu("Level");

        mymbar.add(level);

        help = new JMenu("Help");

        JMenuItem creator = new JMenuItem("Creator");
        JMenuItem instruction = new JMenuItem("Instruction");

        creator.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(p2, "A message.");
            }
        });

        help.add(creator);
        help.add(instruction);
        mymbar.add(help);

        setJMenuBar(mymbar);
    }

    void reset() {
        /*myvalue();
        p1.removeAll();

        myt.stop();

        firstsnake();
        t.setText("Score==>" + score);

        myt = new Thread(this);
        myt.start();*/
    	terminate = true;
    	new Snake();
    	
    }

    void growup() {
    	if (gu == SNAKE_STRING.length()) {
    		for (int i = 0; i < gu; i++) {
                lbp[i] = lb[i].getLocation();
            }

            lbx[0] += directionx;
            lby[0] += directiony;
            lb[0].setBounds(lbx[0], lby[0], PIECE_WIDTH, PIECE_HEIGHT);

            for (int i = 1; i < gu; i++) {
                lb[i].setLocation(lbp[i - 1]);
            }
            Launcher.completionArray[0] = true;
    		largeLabel.setText("You Won!");
    		largeLabel.setVisible(true);
    		terminate = true;
            t.setText("You Won!!! Score ==> " + score);
            try {
    			Thread.sleep(5555);
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
            largeLabel.setVisible(false);
    		return;
    	}
    	if (gu % 10 == 0)
    		speed = speed / 5 * 4;
        lb[gu] = new JButton(SNAKE_STRING.substring(gu, gu+1));
        lb[gu].setMargin(new Insets(0, 0, 0, 0));
        lb[gu].setEnabled(false);
        p1.add(lb[gu]);

        int a = 3*PIECE_WIDTH + (PIECE_WIDTH * r.nextInt(Launcher.WINDOW_WIDTH / PIECE_WIDTH - 10));
        int b = 3*PIECE_HEIGHT + (PIECE_HEIGHT * r.nextInt((Launcher.WINDOW_HEIGHT - SCOREBOARD_HEIGHT) / PIECE_HEIGHT - 10));

        lbx[gu] = a;
        lby[gu] = b;
        lb[gu].setBounds(a, b, PIECE_WIDTH, PIECE_HEIGHT);

        gu++;
    }

    void s_l() {
        for (int i = 0; i < gu; i++) {
            lbp[i] = lb[i].getLocation();
        }

        lbx[0] += directionx;
        lby[0] += directiony;
        lb[0].setBounds(lbx[0], lby[0], PIECE_WIDTH, PIECE_HEIGHT);

        for (int i = 1; i < gu; i++) {
            lb[i].setLocation(lbp[i - 1]);
        }
        
        if (lbx[0] <= 0 || lbx[0] >= x || lby[0] >= y - SCOREBOARD_HEIGHT - 20|| lby[0] <= 0 ) {
        	int remainingI = SNAKE_STRING.length() - gu;
        	String r = ((Integer)remainingI).toString();
        	largeLabel.setText("You lost :(");
        	largeLabel.setVisible(true);
        	try {
				Thread.sleep(5555);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        	largeLabel.setFont(new Font("Verdana", Font.BOLD, 44));
        	largeLabel.setText("You had " + r + " letters left.");
        	terminate = true;
        	return;
        }

        if (lbx[0] == x) {
            lbx[0] = PIECE_WIDTH;
        } else if (lbx[0] == 0) {
            lbx[0] = x - PIECE_WIDTH;
        } else if (lby[0] == y) {
            lby[0] = PIECE_HEIGHT;
        } else if (lby[0] == 0) {
            lby[0] = y - PIECE_HEIGHT;
        }

        if (lbx[0] == lbx[gu - 1] && lby[0] == lby[gu - 1]) {
            food = false;
            score += 5;
            t.setText("Score ==> " + score);
            if (score % 50 == 0 && bonusflag == true) {
                p1.add(bonusfood);
                bonusfood.setBounds((10 * r.nextInt(50)), (10 * r.nextInt(25)), 2*PIECE_WIDTH, 2*PIECE_HEIGHT);//~!~
                bfp = bonusfood.getLocation();
                bonusflag = false;
            }
        }

        if (bonusflag == false) {
            if (bfp.x <= lbx[0] && bfp.y <= lby[0] && bfp.x + PIECE_WIDTH >= lbx[0] && bfp.y + PIECE_HEIGHT >= lby[0]) {
                p1.remove(bonusfood);
                score += 100;
                t.setText("Score ==> " + score);
                bonusflag = true;
            }
        }

        if (food == false) {
            growup();
            food = true;
        } else {
            lb[gu - 1].setBounds(lbx[gu - 1], lby[gu - 1], PIECE_WIDTH, PIECE_HEIGHT);
        }

        /*for(int i=1;i<gu;i++)
        {
        if(lbp[0]==lbp[i])
        {
        t.setText("GAME OVER	"+score);
        try
        {
        myt.join();
        }
        catch(InterruptedException ie)
        {}
        break;
        }
        }*/

        p1.repaint();
    }

    public void keyPressed(KeyEvent e) {

        if (runl == true && e.getKeyCode() == 37) {
            directionx = -PIECE_WIDTH;
            directiony = 0;
            runr = false;
            runu = true;
            rund = true;
        }

        if (runu == true && e.getKeyCode() == 38) {
            directionx = 0;
            directiony = -PIECE_HEIGHT;
            rund = false;
            runr = true;
            runl = true;
        }
        if (runr == true && e.getKeyCode() == 39) {
            directionx = +PIECE_WIDTH;
            directiony = 0;
            runl = false;
            runu = true;
            rund = true;
        }
        if (rund == true && e.getKeyCode() == 40) {
            directionx = 0;
            directiony = +PIECE_WIDTH;
            runu = false;
            runr = true;
            runl = true;
        }
    }

    public void keyReleased(KeyEvent e) { }
    public void keyTyped(KeyEvent e) { }
    
    boolean terminate = false;
    public void run() {
    	largeLabel.setVisible(true);
    	largeLabel.setSize(Launcher.WINDOW_WIDTH, Launcher.WINDOW_HEIGHT);
    	largeLabel.setFont(new Font("Verdana", Font.BOLD, 84));
    	largeLabel.setForeground(Color.RED);
    	for (int i = 3; i > 0; i--){
    		largeLabel.setText("Starting in " + ((Integer) i).toString());
    		try {
				Thread.sleep(990);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    	largeLabel.setVisible(false);
        while (!terminate) {
            s_l();
            try {
                Thread.sleep(speed);
            } catch (InterruptedException ie) {
            }
        }
    }
    
    //Note the string must be longer than 3 characters
    private static final String SNAKE_STRING = "This i";
    
    private static final int PIECE_WIDTH = 17;
    private static final int PIECE_HEIGHT = 17;
    private static final int SCOREBOARD_HEIGHT = 40;
}
